/***************************************************************************
 *   mgpi_g3dmdl.h - 3D Graphics Declarations                              *
 *   Copyright (C) 2008 by cmaster.matso                                   *
 *   cmaster.matso@gmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef _G3DMDL_H
#define _G3DMDL_H

#ifdef __cplusplus
extern "C" {
#endif

#include "../../grbclr/src/mgpi_grbclr.h"
//#include "mdl.h"
//#include "md2.h"
#include "md5model.h"
//#include "smd.h"
#include "obj.h"
#include "hmp.h"
#include "sbx.h"
//#include "x.h"
//#include "assimp/cimport.h"				// TODO: integrate the usage of the feature into the engine
//#include "assimp/scene.h"

#define MGPI_AXISX 0                                                            /** X axis index */
#define MGPI_AXISY 1                                                            /** Y axis index */
#define MGPI_AXISZ 2                                                            /** Z axis index */

#define MGPI_CAMERA_POSITION    300                                             /** camera position property ID */
#define MGPI_CAMERA_UP  301                                                     /** camera up vector property ID */
#define MGPI_CAMERA_RIGHT   302                                                 /** camera right vector property ID */
#define MGPI_CAMERA_FORWARD 303                                                 /** camera forward vector property ID */
#define MGPI_CAMERA_FAR 304                                                     /** camera far clipping plane distance property ID */
#define MGPI_CAMERA_NEAR    305                                                 /** camera near clipping plane distance property ID */
#define MGPI_CAMERA_ORIGHT  306                                                 /** camera orth. right clipping plane dist. property ID */
#define MGPI_CAMERA_OLEFT   307                                                 /** camera orth. left clipping plane dist. property ID */
#define MGPI_CAMERA_BOTTOM  308                                                 /** camera orth. bottom clipping plane dist. property ID */
#define MGPI_CAMERA_TOP 309                                                     /** camera orth. top clipping plane dist. property ID */
#define MGPI_CAMERA_ROTATION_MODE    310                                        /** camera rotation mode property ID */
#define MGPI_CAMERA_YAW_PITCH_ROLL  311                                         /** camera yaw/pitch/roll rotation mode */
#define MGPI_CAMERA_MAX_YAW_PITCH_ROLL  312                                     /** camera max yaw/pitch/roll vector property ID */
#define MGPI_CAMERA_MIN_YAW_PITCH_ROLL  313                                     /** camera min yaw/pitch/roll vector property ID */
#define MGPI_CAMERA_QUATERNIONS  314                                            /** camera quaternions rotation mode */
#define MGPI_CAMERA_FOVY 315                                                    /** camera field-of-view (along Y axis) angle property ID */
#define MGPI_CAMERA_VIEWPORT    316                                             /** camera viewport property ID */
#define MGPI_PERSPECTIVE    317                                                 /** perspective camera mode */
#define MGPI_ORTHOGRAPHIC   318                                                 /** orthographic camera mode */
#define MGPI_WORLD  319                                                         /** world space transformations mode */
#define MGPI_VIEW 320                                                           /** view space transformation mode */

#define MGPI_MAX_SCENE_CAMERAS  32                                              /** max number of camers on the single scene */

#pragma pack(push, 1)

    typedef struct _cparticle {
        float4 rgba;															/** RGBA color */
        float4 normal;															/** normal vector */
        float4 point;															/** particle position */
    } cparticle_t;																/** color particle */

    typedef struct _cam {
        int used;																/** usage flag - used for camera definition */
        int mode;																/** camera rotation mode */
        int is_perspective;														/** flag indicating whether the camera is perspective or not */
        int w;																	/** camera viewport width */
        int h;																	/** camera viewport height */
        float3 yaw_pitch_roll;													/** yaw, pitch and roll angles vector */
        double max_ypr[3];														/** max values of the yaw, pitch and roll angles vector */
        double min_ypr[3];														/** min values of the yaw, pitch and roll angles vector */
        float4 position;														/** camera 3D position */
        float4 u;																/** camera up vector */
        float4 r;																/** camera right vector */
        float4 f;																/** camera forword vector */
        float fovy;																/** field-of-view (along Y axis) angle */
        float top_clip_dist;													/** top clipping plane distance */
        float bottom_clip_dist;													/** bottom clipping plane distance */
        float far_clip_dist;													/** far clipping plane distance */
        float near_clip_dist;													/** near clipping plane distance */
        float left_clip_dist;													/** left clipping plane distance */
        float right_clip_dist;													/** right clipping plane distance */
    } cam_t;																	/** vector camera */

#pragma pack(pop)

    cam_t g_aSceneCameras[MGPI_MAX_SCENE_CAMERAS];								/** engine cameras */
    int g_nHandleBase, g_nCurrentCameraHandle;									/** current camera handle */
    GLfloat *g_fModelView;														/** auxiliary model-view matrix */
    GLfloat *g_fProjection;														/** auxiliary projection matrix */

    /**
     * Builds a RGB texture 2D of the given pixels array.
     */
    int MGPI_API g3dGenTexture2DRGB(GLubyte *raw_pixs, int w, int h);

    /**
     * Builds a RGBA texture 2D of the given pixels array.
     */
    int MGPI_API g3dGenTexture2DRGBA(GLubyte *raw_pixs, int w, int h);

    /**
     * Builds a given type of texture 2D of the given pixels array.
     */
    int MGPI_API g3dGenTexture2DType(GLubyte *raw_pixs, GLenum type, int w, int h);

    /**
     * Builds a given type of texture 2D of the given pixels array.
     * Texture parameter configuration is user defined.
     */
    int MGPI_API g3dGenTexture2DTypeConf(GLubyte *raw_pixs, GLenum type, int w, int h, void (*config)(void));

#ifdef GL_ARB_texture_float

    /**
     * Builds a given type of float texture 2D of the given pixels array.
     */
    int MGPI_API g3dGenTexture2DTypeFloat(GLubyte *raw_pixels, GLenum format, GLenum internal, int w, int h);
#endif

#ifdef GL_ARB_texture_rectangle

    /**
     * Builds a RGB texture rectangle of the given pixels array.
     */
    int MGPI_API g3dGenTextureRectRGB(GLubyte *raw_pixels, int w, int h);

    /**
     * Builds a RGBA texture rectangle of the given pixels array.
     */
    int MGPI_API g3dGenTextureRectRGBA(GLubyte *raw_pixels, int w, int h);

    /**
     * Builds a given type of texture rectangle of the given pixels array.
     */
    int MGPI_API g3dGenTextureRectType(GLubyte *raw_pixels, GLenum type, int w, int h);

/*#ifdef GL_ARB_texture_float (?)
    int MGPI_API g3dGenTextureRectTypeFloat(GLubyte *, GLenum, GLenum, int, int);
#endif*/

#endif

    /**
     * Builds a RGB texture cube of the given pixels array.
     */
    int MGPI_API g3dGenTextureCubeRGB(GLubyte *raw_pixels[6], int w, int h);

    /**
      * Builds a RGB texture cube of the given pixels array.
      */
    int MGPI_API g3dGenTextureCubeBGR(GLubyte *raw_pixels[6], int w, int h);

    /**
     * Builds a RGBA texture cube of the given pixels array.
     */
    int MGPI_API g3dGenTextureCubeRGBA(GLubyte *raw_pixels[6], int w, int h);

    /**
     * Builds a given type of texture cube of the given pixels array.
     */
    int MGPI_API g3dGenTextureCubeType(GLubyte *raw_pixels[6], GLenum type, int w, int h);

#ifdef GL_ARB_texture_float

    /**
     * Builds a given type of float texture cube of the given pixels array.
     */
    int MGPI_API g3dGenTextureCubeTypeFloat(GLubyte* raw_pixels[6], GLenum format, GLenum internal, int w, int h);
#endif

	/**
	 * Creates an empty texture 2D object.
	 */
	int MGPI_API g3dGenEmptyTexture2D(int w, int h, int type, int iformat, int format, GLenum target);

	/**
	 * Copy image data from one texture to another. (TODO: do it using FBO)
	 */
	void MGPI_API g3dCopyTexture2D(GLenum type, GLenum format, int w, int h, GLuint src, GLuint dest);

	/**
	 * Prepares pixel buffer object for texture image data transfer
	 */
	void MGPI_API g3dPreparePixelBuffer(int w, int h, int pixel_size);

    /**
     * Loads a texture 2D from file.
     */
    int MGPI_API g3dTexture2DType(const char *name, GLuint type);

    /**
     * Loads a float texture 2D from file.
     */
    int MGPI_API g3dTexture2DTypeFloat(const char *name, GLuint type, GLuint internal);

    /**
     * Creates a render buffer of the given size and internal format.
     */
    int MGPI_API g3dGenRenderbuffer(GLenum internal_format, int w, int h);

	/**
     * Creates a multisample render buffer of the given size and internal format.
     */
    int MGPI_API g3dGenMultisampleRenderbuffer(GLenum internal_format, int w, int h, int samples);

    /**
     * Creates and returns a rotation matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenRotationMatrixf(float angle, float x, float y, float z);

    /**
     * Creates and returns a rotation matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenRotationMatrixv(float angle, float4 axis);

    /**
     * Creates and returns a rotation matrix for the given orientation quaternion.
     */
    float MGPI_API *g3dGenRotationMatrixq(quat_t orientation);

    /**
     * Creates and returns a translation matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenTranslationMatrixf(float x, float y, float z);

    /**
     * Creates and returns a translation matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenTranslationMatrixv(float4 vect);

    /**
     * Creates and returns a scaling matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenScalingMatrixf(float x, float y, float z);

    /**
     * Creates and returns a scaling matrix of the given parameters, in a form of a float pointer.
     */
    float MGPI_API *g3dGenScalingMatrixv(float4 vect);

    /**
     * Creates and return a shear matrix containing skews of X, Y and Z axis.
     */
    float MGPI_API *g3dGenShearMatrixf(float skewX, float skewY, float skewOnX, float skewOnY);

    /**
     * Sets the given vector as an input transformation vector.
     */
    int MGPI_API g3dInputv(float4 pos);

    /**
     * Sets the given values as an input transformation vector.
     */
    int MGPI_API g3dInputf(float x, float y, float z);

    /**
     * Sets the given values as an input transformation vector.
     */
    int MGPI_API g3dInputi(int x, int y, int z);

    /**
     * Rotates a point over an axis by the angle given.
     */
    int MGPI_API g3dRotatef(float angel, float4 axis);

    /**
     * Rotates a point over an axis by the angle given.
     */
    int MGPI_API g3dRotatei(int angle, float4 axis);

    /**
     * Rotates a point using the given rotation matrix.
     */
    int MGPI_API g3dRotatem(float4x4 m);

    /**
     * Causes the input transformation vector to be translated by the given vector.
     */
    int MGPI_API g3dTranslatev(float4 move);

    /**
     * Causes the input transformation vector to be translated by the given values.
     */
    int MGPI_API g3dTranslatef(float dx, float dy, float dz);

    /**
     * Causes the input transformation vector to be translated by the given values.
     */
    int MGPI_API g3dTranslatei(int dx, int dy, int dz);

    /**
     * Scales a point using the given scale vector.
     */
    int MGPI_API g3dScalev(float4 scale);

    /**
     * Scales a point using the given scale float values.
     */
    int MGPI_API g3dScalef(float x, float y, float z);

    /**
     * Scales a point using the given scale int values.
     */
    int MGPI_API g3dScalei(int x, int y, int z);

    /**
     * Gets an output transformation vector and causes the input to be cleared.
     */
    int MGPI_API g3dOutputv(float4 *point);

    /**
     * Multiplies given input vector with the current transformation matrix.
     */
    int MGPI_API g3dTransform(float4 *product);

    /**
     * Loads an identity matrix to the trasformation matrix.
     */
    int MGPI_API g3dLoadIdentity(void);

    /**
     * Loads a given matrix as transformation matrix.
     */
    int MGPI_API g3dLoadMatrix(float4x4 m);

    /**
     * Allocates a camera object in the engine memory. The position is set to the given.
     */
    int MGPI_API g3dAllocVectCam(float4 point);

    /**
     * Sets a given camera view port with the given sizes.
     */
    int MGPI_API g3dSetCamViewport(int cam, int w, int h);

    /**
     * Gets a defined by the parameter given camera vector.
     */
    int MGPI_API g3dGetCamVect(float4 *pv, int cam, int param);

    /**
     * Sets camera vectors.
     */
    int MGPI_API g3dSetCamVect(float4 vector, int cam, int param);

    /**
     * Sets the given camera as the current camera.
     */
    int MGPI_API g3dSetCurrentCam(int camera);

    /**
     * Sets camera rotation mode.
     */
    int MGPI_API g3dSetCamMode(int cam, int mode);

    /**
     * Frees the given camera form the engive memory.
     */
    int MGPI_API g3dFreeVectorCam(int cam);

    /**
     * Rotates the given camera over the given axis by the given angle.
     */
    int MGPI_API g3dRotateCamf(int cam, float angel, float4 axis);

    /**
     * Rotates the given camera over the given axis by the given angle.
     */
    int MGPI_API g3dRotateCami(int cam, int angel, float4 axis);

    /**
     * Rotates the given camera by the yaw, pitch and roll angles.
     */
    int MGPI_API g3dRotateCamypr(int cam, float yaw, float pitch, float roll);

    /**
     * Translates the given camera by the given vector.
     */
    int MGPI_API g3dTranslateCamv(int cam, float4 move);

    /**
     * Translates the given camera by the given values.
     */
    int MGPI_API g3dTranslateCamf(int cam, float dx, float dy, float dz);

    /**
     * Translates the given camera by the given values.
     */
    int MGPI_API g3dTranslateCami(int cam, int dx, int dy, int dz);

    /**
     * Changes the value of the given camera field-of-view angle by the given zoom.
     */
    int MGPI_API g3dZoomCamf(int cam, float zoom);

    /**
     * Changes the value of the given camera field-of-view angle by the given zoom.
     */
    int MGPI_API g3dZoomCami(int cam, int zoom);

#define g3dZoomIn(cam) g3dZoomCamf(cam,-0.5f)       /** camera zoom in macro */
#define g3dZoomOut(cam) g3dZoomCamf(cam,0.5f)       /** camera zoom out macro */

    /**
     * Rebuilds a projection matrix for an orthographic camera to defalut values.
     */
    int MGPI_API g3dOrthReshape(int w, int h);

    /**
     * Rebuilds a projection matrix for an perspective camera to defalut values.
     */
    int MGPI_API g3dPersReshape(int w, int h);

    /**
     * Rebuilds a projection matrix for the given perspective camera.
     */
    int MGPI_API g3dCameraOrthReshape(int cam);

    /**
     * Rebuilds a projection matrix for the given orthographic camera.
     */
    int MGPI_API g3dCameraPersReshape(int cam);

    /**
     * Rebuilds a model view matrix for the given camera.
     */
    int MGPI_API g3dUpdateCam(int cam);

    /**
     * Draws coordinates system vectors.
     */
    void MGPI_API g3dDrawCoordinates(void);

    /**
     * Draws a wired box.
     */
    void MGPI_API g3dDrawWireBox(GLfloat lsize, GLfloat r, GLfloat g, GLfloat b);

    /**
     * Draws a wired box.
     */
    void MGPI_API g3dDrawWirePiramid(GLfloat lsize, GLfloat r, GLfloat g, GLfloat b);

    /**
     * Draws a grid.
     */
    void MGPI_API g3dDrawGrid(GLfloat fExtent, GLfloat fStep, GLfloat y, GLfloat r, GLfloat g, GLfloat b);

    /**
     * Draw the texture on the quad given using the given program.
     */
    void MGPI_API g3dDrawTexture2D(int tex, GLuint program, float2 scale);

    /**
     * Draws a standard teapot.
     */
    void MGPI_API g3dDrawTeapot(float size, int texture, GLuint program);

    /**
     * Draws a standard 3D quad.
     */
    void MGPI_API g3dDrawQuad();

    /**
     * Sets up a view matrix.
     */
    void MGPI_API g3dLookAt(float4 position, float4 look_at, float4 up);

    /** ?????
     * Sets up a viewport transformation.
     */
    void MGPI_API g3dViewport(float x, float y, float w, float h);

    /**
     * Sets up perspective projection matrix.
     */
    void MGPI_API g3dPerspective(float fovy, float aspect, float near_clip_dist, float far_clip_dist);

    /**
     * Sets up orthographic projection matrix.
     */
    void MGPI_API g3dOrthographic(float near_clip_dist, float far_clip_dist, float left_clip_dist, float right_clip_dist, float bottom_clip_dist, float top_clip_dist);

    /**
     * Multiplies the given input vector by the view and projection matrices.
     * The product is acquired as follows:
     * product = ((view * projection) * vector)
     */
    void MGPI_API g3dViewProjection(float4 *product);

    /**
     * Returns a world matrix in a form of a row oriented array.
     */
    float MGPI_API *g3dGetWorldMatrix(void);

    /**
     * Returns a view matrix in a form of a row oriented array.
     */
    float MGPI_API *g3dGetViewMatrix(void);

    /**
     * Returns a projection matrix in a form of a row oriented array.
     */
    float MGPI_API *g3dGetProjectionMatrix(void);

#ifdef __cplusplus
}
#endif

#endif
